package com.uinnova.product.eam.service.bm.impl;

import com.alibaba.fastjson.JSON;
import com.binary.core.util.BinaryUtils;
import com.binary.jdbc.Page;
import com.google.common.collect.Lists;
import com.uinnova.product.eam.base.util.EamUtil;
import com.uinnova.product.eam.comm.model.es.EamCategory;
import com.uinnova.product.eam.comm.model.es.EamMultiModelHierarchy;
import com.uinnova.product.eam.model.*;
import com.uinnova.product.eam.model.bm.*;
import com.uinnova.product.eam.model.dto.EamHierarchyDto;
import com.uinnova.product.eam.model.enums.ArtifactType;
import com.uinnova.product.eam.model.enums.CategoryTypeEnum;
import com.uinnova.product.eam.service.*;
import com.uinnova.product.eam.service.asset.BmConfigSvc;
import com.uinnova.product.eam.service.bm.IEamFlowModelSvc;
import com.uinnova.product.eam.service.bm.QuickDrawingSvc;
import com.uinnova.product.eam.service.impl.IamsCIPrivateSvc;
import com.uinnova.product.eam.service.impl.IamsCIRltSwitchSvc;
import com.uinnova.product.vmdb.comm.bean.CIState;
import com.uinnova.product.vmdb.comm.model.ci.CcCi;
import com.uinnova.product.vmdb.provider.ci.bean.CcCiClassInfo;
import com.uinnova.product.vmdb.provider.ci.bean.CcCiInfo;
import com.uinnova.product.vmdb.provider.rlt.bean.CcCiRltInfo;
import com.uinnova.project.api.diagram.v2.client.ESDiagramApiClient;
import com.uinnova.project.base.diagram.comm.model.ESDiagram;
import com.uino.api.client.cmdb.ICIClassApiSvc;
import com.uino.bean.cmdb.base.ESCIClassInfo;
import com.uino.bean.cmdb.base.ESCIInfo;
import com.uino.bean.cmdb.base.LibType;
import com.uino.bean.cmdb.business.BindCiRltRequestDto;
import com.uino.bean.cmdb.query.ESCISearchBean;
import com.uino.bean.permission.base.SysUser;
import com.uino.util.sys.SysUtil;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.collections4.comparators.NullComparator;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 自动成图
 * @author ch
 * @date 2022/5/11
 */
@Service
public class QuickDrawing implements QuickDrawingSvc {

    private static final String NUMBER = "序号";
    private static final String SUFFIX = "关系未获取到相关数据!";
    private static final String RULE_CLASS ="DTEA-业务规则";
    private static final String RULE_CLASS_CONFIG ="RULE_CLASS_CONFIG";


    @Resource
    private EamCategorySvc categorySvc;
    @Resource
    private IBmHierarchySvc hierarchySvc;
    @Resource
    private IBmMultiModelHierarchySvc modelHierarchySvc;
    @Resource
    private ICISwitchSvc ciSwitchSvc;
    @Resource
    private IamsCIPrivateSvc ciPrivateSvc;
    @Resource
    private IamsCIRltSwitchSvc rltSwitchSvc;
    @Resource
    private IEamCIClassApiSvc ciClassApiSvc;
    @Resource
    private ICIClassApiSvc iciClassApiSvc;
    @Resource
    private IEamArtifactColumnSvc artifactSvc;
    @Resource
    private IEamFlowModelSvc flowModelSvc;
    @Autowired
    private ESDiagramApiClient diagramApiClient;
    @Resource
    private IEamDiagramSvcV2 eamDiagramSvcV2;
    @Resource
    private BmConfigSvc bmConfigSvc;

    private static final Logger log = LoggerFactory.getLogger(QuickDrawing.class);

    @Override
    public QuickDrawingResp quickDrawing(QuickDrawingDto dto) {
        QuickDrawingResp result = new QuickDrawingResp();
        SysUser user = SysUtil.getCurrentUserInfo();
        Long domainId = user.getDomainId();
        dto.setDomainId(domainId);
        ESDiagram diagram = diagramApiClient.getEsDiagram(dto.getDiagramId(), 0);
        if(diagram == null){
            result.setMessage("当前视图已被删除,无法操作!");
            return result;
        }
        EamCategory category = categorySvc.getById(diagram.getDirId(), LibType.PRIVATE);
        if(BinaryUtils.isEmpty(category) || !category.getType().equals(CategoryTypeEnum.MODEL.val())){
            result.setMessage("无法获取当前视图关联的模型信息!");
            return result;
        }
        dto.setCategory(category);
        EamMultiModelHierarchy model = modelHierarchySvc.getModelById(category.getModelId());
        if(BinaryUtils.isEmpty(model) || model.getDataStatus()==0 || model.getReleaseState()==0){
            result.setMessage("当前模型关联模型工艺未发布/已删除,请联系管理员!");
            return result;
        }
        EamCategory modelRoot = categorySvc.getModelRoot(category.getModelId(), dto.getOwnerCode(), dto.getLibType());
        int dirLvl = category.getDirLvl() - modelRoot.getDirLvl() - 1;
        EamHierarchyDto hierarchy = hierarchySvc.queryByLvlAndModelId(dirLvl, category.getModelId(), dto.getDomainId());
        if(BinaryUtils.isEmpty(hierarchy) || BinaryUtils.isEmpty(hierarchy.getArtifactId())){
            result.setMessage("层级配置未完善,无法自动成图,请联系管理员!");
            return result;
        }
        boolean checkCiUpdate = checkArtifactCiUpdate(hierarchy);
        if(checkCiUpdate){
            result.setMessage("当前视图绑定的制品类型架构元素已更新,请联系管理员更新层级配置信息!");
            return result;
        }
        boolean checkRltUpdate = checkArtifactRltUpdate(hierarchy);
        if(checkRltUpdate){
            result.setMessage("当前视图绑定的制品类型关系配置已更新,请联系管理员更新层级配置信息!");
            return result;
        }
        //校验制品中关系是否已更新
        dto.setHierarchy(hierarchy);
        dto.setCiCode(category.getCiCode());
        if(hierarchy.getDirLvl() != 0){
            List<ESCIInfo> ciList = ciSwitchSvc.getCiByCodes(Collections.singletonList(category.getCiCode()), dto.getOwnerCode(), LibType.PRIVATE);
            if(BinaryUtils.isEmpty(ciList)){
                result.setMessage("该视图绑定的对象数据已被删除,请检查!");
                return result;
            }
            dto.setCi(ciList.get(0));
        }
        if((hierarchy.getDirLvl() == 0)){
             drawingTop(dto, result);
        } else if(!BinaryUtils.isEmpty(hierarchy.getRltList()) && hierarchy.getRltList().size() == 1){
            drawingByOneRlt(dto, result);
        } else if(!BinaryUtils.isEmpty(hierarchy.getRltList()) && hierarchy.getRltList().size() == 2){
            drawingByTwoRlt(dto, result);
        } else {
          result.setMessage("模型配置成图查询数据配置有误,无法自动成图,请联系管理员!");
        }
        return result;
    }

    /**
     * 校验制品中架构元素是否已更新
     * @param hierarchy 层级配置
     * @return 是否已更新
     */
    private boolean checkArtifactCiUpdate(EamHierarchyDto hierarchy) {
        List<EamArtifactElementVo> elementVos = artifactSvc.queryByArtifactId(hierarchy.getArtifactId(), Collections.singletonList(ArtifactType.ASSET_TYPE.val()));
        if(BinaryUtils.isEmpty(hierarchy.getEffectClassId()) || hierarchy.getEffectClassId().equals(0L)){
            return false;
        }
        if(CollectionUtils.isEmpty(elementVos)){
            return true;
        }
        for (EamArtifactElementVo each : elementVos) {
            List<EamArtifactCiVo> elementObj = each.getElementCiObj();
            for (EamArtifactCiVo ciVo : elementObj) {
                if(hierarchy.getEffectClassId().toString().equals(ciVo.getId())){
                    return false;
                }
            }
        }
        return true;
    }

    /**
     * 校验制品中关系配置是否已更新
     * @param hierarchy 层级配置
     * @return 是否已更新
     */
    private boolean checkArtifactRltUpdate(EamHierarchyDto hierarchy) {
        List<EamArtifactElementVo> elementVos = artifactSvc.queryByArtifactId(hierarchy.getArtifactId(), Lists.newArrayList(ArtifactType.RLT_TYPE.val()));
        if(CollectionUtils.isEmpty(hierarchy.getRltList())){
            return false;
        }
        if(CollectionUtils.isEmpty(elementVos)){
            return true;
        }
        List<EamArtifactRltVo> ciElements = elementVos.stream().map(EamArtifactElementVo::getElementRltObj).flatMap(Collection::stream).collect(Collectors.toList());
        List<String> keys = new ArrayList<>();
        for (EamArtifactRltVo each : ciElements) {
            if(each.getViewFlag() != null && each.getViewFlag()){
                String key = each.getSourceCiInfo().getId() + "-" + each.getRltClassInfo().getCiClass().getId() + "-" + each.getTargetCiInfo().getId();
                keys.add(key);
            }
        }
        for (EamArtifactRltVo each : hierarchy.getRltList()) {
            String key = each.getSourceCiInfo().getId() + "-" + each.getRltClassInfo().getCiClass().getId() + "-" + each.getTargetCiInfo().getId();
            if(!keys.contains(key)){
                return true;
            }
        }
        return false;
    }

    @Override
    public List<CcCiInfo> getRulesByStep(QuickDrawingDto drawingDto) {
        Long diagramId = diagramApiClient.queryDiagramInfoByEnergy(drawingDto.getDiagramId());
        ESDiagram diagram = diagramApiClient.querySimpleDiagramInfoById(diagramId);
        //查询制品中配置的步骤和规则的关系
        if(BinaryUtils.isEmpty(diagram.getViewType())){
            return Collections.emptyList();
        }
        String ownerCode = diagram.getOwnerCode();
        List<ESCIInfo> stepList = ciSwitchSvc.getCiByCodes(Lists.newArrayList(drawingDto.getCiCode()), ownerCode, drawingDto.getLibType());
        if(BinaryUtils.isEmpty(stepList)){
            return Collections.emptyList();
        }
        ESCIInfo step = stepList.get(0);
        Long stepClassId = step.getClassId();
        List<EamArtifactElementVo> elementVos = artifactSvc.queryByArtifactId(Long.parseLong(diagram.getViewType()), Lists.newArrayList(ArtifactType.RLT_TYPE.val()));
        if(BinaryUtils.isEmpty(elementVos)){
            return Collections.emptyList();
        }
        String configJson = bmConfigSvc.getConfigType(RULE_CLASS_CONFIG);
        if(BinaryUtils.isEmpty(configJson)){
            configJson = RULE_CLASS;
        }
        List<EamArtifactRltVo> ciElements = elementVos.stream().map(EamArtifactElementVo::getElementRltObj).flatMap(Collection::stream).collect(Collectors.toList());
        List<EamArtifactRltVo> rltList = new ArrayList<>();
        for (EamArtifactRltVo each : ciElements) {
            String sourceClassCode = each.getSourceCiInfo().getClassCode();
            String targetClassCode = each.getTargetCiInfo().getClassCode();
            if((configJson.equals(sourceClassCode) && each.getTargetCiInfo().getId().equals(stepClassId)) ||
                    (configJson.equals(targetClassCode) && each.getSourceCiInfo().getId().equals(stepClassId))){
                rltList.add(each);
            }
        }
        if(BinaryUtils.isEmpty(rltList)){
            return Collections.emptyList();
        }
        Long stepId = step.getId();
        List<CcCiInfo> ruleList = new ArrayList<>();
        CcCiClassInfo ruleClass = ciClassApiSvc.getCIClassByCodes(configJson);
        //如果从设计库拖出步骤，将相关规则和关系存入私有库
        if(LibType.DESIGN.equals(drawingDto.getLibType())){
            ESCIClassInfo stepClass = ciClassApiSvc.queryClassById(stepClassId);
            CcCiInfo stepNew = EamUtil.coverESCIInfo(step, stepClass.getCcAttrDefs(), stepClass);
            stepNew.getCi().setOwnerCode(ownerCode);
            stepNew.getCi().setId(null);
            stepId = ciSwitchSvc.saveOrUpdateCI(stepNew, LibType.PRIVATE);
            List<CcCiInfo> designRuleList = getRuleByRlt(step.getClassId(), rltList, step.getId(), ownerCode, LibType.DESIGN);
            if(!BinaryUtils.isEmpty(designRuleList)) {
                //copy实体属性到私有库
                List<ESCIInfo> coverCiList = EamUtil.coverCiInfoList(designRuleList);
                for (ESCIInfo each : coverCiList) {
                    each.setId(null);
                    each.setOwnerCode(ownerCode);
                }
                List<Long> classId = Lists.newArrayList(ruleClass.getCiClass().getId());
                Map<String, SavePrivateBatchCIContext> contextMap = ciPrivateSvc.saveOrUpdateBatchCI(coverCiList, classId, ownerCode, ownerCode);
                for (SavePrivateBatchCIContext each : contextMap.values()) {
                    CcCiInfo rule = EamUtil.coverESCIInfo(each.getEsCi(), ruleClass.getAttrDefs(), ruleClass.getCiClass());
                    ruleList.add(rule);
                }
            }
        }
        List<CcCiInfo> privateRuleList = getRuleByRlt(stepClassId, rltList, stepId, ownerCode, LibType.PRIVATE);
        if(!BinaryUtils.isEmpty(privateRuleList)){
            ruleList.addAll(privateRuleList);
        }
        //结果集为空时，添加一条新的空白规则
        if(CollectionUtils.isEmpty(ruleList)){
            ruleList.add(createBlankRule(stepId, ruleClass.getCiClass().getId(), drawingDto.getDiagramId(), rltList, ownerCode));
        }
        Map<String, CcCiInfo> distinctMap = ruleList.stream().collect(Collectors.toMap(each -> each.getCi().getCiCode(), each -> each, (k1, k2) -> k2));
        ruleList = Lists.newArrayList(distinctMap.values());
        ruleClass.getAttrDefs().forEach(each -> each.setClassId(ruleClass.getCiClass().getId()));
        for (CcCiInfo ciInfo : ruleList) {
            ciInfo.setCiClass(ruleClass.getCiClass());
            ciInfo.setAttrDefs(ruleClass.getAttrDefs());
        }
        return ruleList;
    }

    private CcCiInfo createBlankRule(Long stepId, Long ruleClassId, String diagramId,List<EamArtifactRltVo> rltList, String ownerCode){
        CcCiInfo rule = new CcCiInfo();
        rule.setCi(new CcCi());
        rule.setAttrs(new HashMap<>());
        rule.getCi().setClassId(ruleClassId);
        rule.getCi().setDiagramId(diagramId);
        rule.getCi().setOwnerCode(ownerCode);
        Long ruleId = ciPrivateSvc.saveOrUpdate(rule);
        CcCiInfo ruleInfo = ciPrivateSvc.getCiInfoById(ruleId);
        //创建完成后构建关系
        List<BindCiRltRequestDto> bindList = new ArrayList<>();
        for (EamArtifactRltVo rlt : rltList) {
            Long rltClassId = rlt.getRltClassInfo().getCiClass().getId();
            Long sourceClassId = rlt.getSourceCiInfo().getId();
            Long sourceId = ruleClassId.equals(sourceClassId)?ruleId:stepId;
            Long targetId = ruleClassId.equals(sourceClassId)?stepId:ruleId;
            BindCiRltRequestDto bindRlt = BindCiRltRequestDto.builder().ownerCode(ownerCode).repetitionError(false)
                    .rltClassId(rltClassId).custom1("3").sourceCiId(sourceId).targetCiId(targetId).build();
            bindList.add(bindRlt);
        }
        rltSwitchSvc.bindCiRltBatch(bindList, LibType.PRIVATE);
        return ruleInfo;
    }

    /**
     * 根据步骤及关系分类获取规则
     * @param stepClassId 步骤分类id
     * @param rltList 关系集合
     * @param stepId 步骤id
     * @param ownerCode 用户标识
     * @param libType 库
     * @return 规则code集合
     */
    private List<CcCiInfo> getRuleByRlt(Long stepClassId, List<EamArtifactRltVo> rltList, Long stepId, String ownerCode, LibType libType) {
        List<CcCiInfo> result = new ArrayList<>();
        for (EamArtifactRltVo rlt : rltList) {
            List<Long> rltId = Collections.singletonList(rlt.getRltClassInfo().getCiClass().getId());
            Long sourceClassId = rlt.getSourceCiInfo().getId();
            Long targetClassId = rlt.getTargetCiInfo().getId();
            List<CcCiRltInfo> rltData = rltSwitchSvc.getRltInfoByClassId(rltId, sourceClassId, targetClassId, ownerCode, libType);
            if(BinaryUtils.isEmpty(rltData)){
                continue;
            }
            List<CcCiInfo> ruleList;
            if(stepClassId.equals(sourceClassId)){
                ruleList = rltData.stream().filter(each -> each.getSourceCiInfo().getCi().getId().equals(stepId))
                        .map(CcCiRltInfo::getTargetCiInfo).distinct().collect(Collectors.toList());
            } else {
                ruleList = rltData.stream().filter(each -> each.getTargetCiInfo().getCi().getId().equals(stepId))
                        .map(CcCiRltInfo::getSourceCiInfo).distinct().collect(Collectors.toList());
            }
            result.addAll(ruleList);
        }
        Map<String, CcCiInfo> resultMap = result.stream().collect(Collectors.toMap(each -> each.getCi().getCiPrimaryKey(), each -> each, (k1, k2) -> k2));
        return Lists.newArrayList(resultMap.values());
    }

    /**
     * 删除作废目录
     */
    private void removeCatalog(QuickDrawingDto dto, Collection<String> resultCodes){
        EamCategoryCdt cdt = new EamCategoryCdt();
        cdt.setDelType(0);
        cdt.setCiCodes(new ArrayList<>(resultCodes));
        cdt.setDiagramId(dto.getDiagramId());
        eamDiagramSvcV2.removeCiInDiagram(cdt);
    }

    /**
     * 顶级视图成图
     */
    private void drawingTop(QuickDrawingDto dto, QuickDrawingResp resp){
        String loginCode = SysUtil.getCurrentUserInfo().getLoginCode();
        EamHierarchyDto hierarchy = dto.getHierarchy();
        if(BinaryUtils.isEmpty(hierarchy.getEffectClassId()) || hierarchy.getEffectClassId().equals(0L) || BinaryUtils.isEmpty(hierarchy.getShape()) || "0".equals(hierarchy.getShape())){
            resp.setMessage("未获取到当前视图模型配置信息或模型配置未完善!");
            return;
        }
        //取出层级配置生成下级架构元素分类
        List<ESCIInfo> ciList = queryCiList(null, hierarchy.getEffectClassId(), dto.getOwnerCode());
        if(BinaryUtils.isEmpty(ciList)){
            resp.setMessage("未获取到相关数据，或对象数据业务主键未填写完整!");
            return;
        }
        if(BinaryUtils.isEmpty(dto.getHierarchy().getRltList())){
            //过滤
            Map<String, ESCIInfo> resultMap = ciList.stream().collect(Collectors.toMap(CcCi::getCiCode, each -> each, (k1, k2) -> k2));
            List<ESCIInfo> resultList = Lists.newArrayList(resultMap.values());
            resp.setCi(sortCiList(resultList));
            CcCiClassInfo classInfo = queryClass(hierarchy.getEffectClassId(), hierarchy.getArtifactId());
            resp.setCiClass(classInfo);
            removeCatalog(dto, resultMap.keySet());
        }else if(dto.getHierarchy().getRltList().size() == 1){
            List<EamArtifactRltVo> rltList = dto.getHierarchy().getRltList();
            EamArtifactRltVo rltVo = rltList.get(0);
            Long sourceClassId = rltVo.getSourceCiInfo().getId();
            Long targetClassId = rltVo.getTargetCiInfo().getId();
            VcCiClassInfo rltClass = rltVo.getRltClassInfo();
            List<CcCiRltInfo> rltInfo = rltSwitchSvc.getRltInfoByClassId(Collections.singletonList(rltClass.getCiClass().getId()), sourceClassId, targetClassId, loginCode, LibType.PRIVATE);
            if(BinaryUtils.isEmpty(rltInfo)) {
                resp.setMessage("通过"+rltClass.getCiClass().getClassName()+SUFFIX);
                return;
            }
            List<String> ciCodes = rltInfo.stream().map(each -> each.getTargetCiInfo().getCi().getCiCode()).distinct().collect(Collectors.toList());
            extracted(dto, resp, hierarchy, ciCodes, rltInfo, false);
        }
    }

    /**
     * 通过两条关系数据成图
     */
    private void drawingByTwoRlt(QuickDrawingDto dto, QuickDrawingResp resp){
        ESCIInfo ciInfo = dto.getCi();
        EamHierarchyDto hierarchy = dto.getHierarchy();
        Long classId = ciInfo.getClassId();
        String ciCode = ciInfo.getCiCode();
        EamArtifactRltVo oneRlt = hierarchy.getRltList().get(0);
        EamArtifactRltVo twoRlt = hierarchy.getRltList().get(1);
        //校验第一条关系
        Long oneSourceId = oneRlt.getSourceCiInfo().getId();
        Long oneTargetId = oneRlt.getTargetCiInfo().getId();
        if(!classId.equals(oneSourceId) && !classId.equals(oneTargetId)){
            resp.setMessage("模型配置成图查询数据配置有误!");
            return;
        }
        //校验第二条关系
        Long twoSourceId = twoRlt.getSourceCiInfo().getId();
        Long twoTargetId = twoRlt.getTargetCiInfo().getId();
        boolean oneFlag = classId.equals(oneSourceId) && !twoSourceId.equals(oneTargetId) && !twoTargetId.equals(oneTargetId);
        boolean twoFlag = classId.equals(oneTargetId) && !twoSourceId.equals(oneSourceId) && !twoTargetId.equals(oneSourceId);
        if(oneFlag && twoFlag){
            resp.setMessage("模型配置成图查询数据配置有误!");
            return;
        }
        //根据第一条关系查询相关数据
        List<String> oneCodeList = queryCiCodeByRlt(oneRlt, classId, Lists.newArrayList(ciCode), dto.getOwnerCode());
        if(BinaryUtils.isEmpty(oneCodeList)){
            resp.setMessage("通过"+oneRlt.getRltClassInfo().getCiClass().getClassName()+SUFFIX);
            return;
        }
        //根据第二条关系查询相关数据
        Long twoClassId = classId.equals(oneSourceId)?oneTargetId:oneSourceId;
        Long twoRltClassId = twoRlt.getRltClassInfo().getCiClass().getId();
        List<CcCiRltInfo> twoRltList = rltSwitchSvc.getRltInfoByClassId(Collections.singletonList(twoRltClassId), twoSourceId, twoTargetId, dto.getOwnerCode(), LibType.PRIVATE);
        boolean cover = twoClassId.equals(twoSourceId);
        extracted(dto, resp, hierarchy, oneCodeList, twoRltList, cover);
    }

    private void extracted(QuickDrawingDto dto, QuickDrawingResp resp, EamHierarchyDto hierarchy, List<String> oneCodeList, List<CcCiRltInfo> drawRltList, boolean cover) {
        //查询当前制品所有shape
        Map<String, EamArtifactCiVo> artifactClassMap = getShapeMap(hierarchy.getArtifactId());
        Map<String, Set<CcCiInfo>> ciGroup = new HashMap<>(16);
        Map<String, CcCiInfo> collectMap = new HashMap<>(16);
        for (CcCiRltInfo rltInfo : drawRltList) {
            CcCiInfo collectCi = rltInfo.getSourceCiInfo();
            CcCiInfo groupCi = rltInfo.getTargetCiInfo();
            String ciCode = collectCi.getCi().getCiCode();
            if((cover && !oneCodeList.contains(ciCode)) || (!cover && !oneCodeList.contains(groupCi.getCi().getCiCode()))){
                continue;
            }
            //替换为制品shape
            Long groupClassId = groupCi.getCi().getClassId();
            Long collectClassId = collectCi.getCi().getClassId();
            EamArtifactCiVo groupArtifactVo = artifactClassMap.get(groupClassId.toString());
            if(!BinaryUtils.isEmpty(groupArtifactVo)){
                if(!BinaryUtils.isEmpty(groupArtifactVo.getImgFullName())){
                    groupCi.getCiClass().setShape(groupArtifactVo.getImgFullName());
                }else{
                    groupCi.getCiClass().setShape(groupArtifactVo.getShape());
                }
            }
            groupCi.getCiClass().setIcon(groupArtifactVo.getIcon());
            EamArtifactCiVo collectArtifactCiVo = artifactClassMap.get(collectClassId.toString());
            if(!BinaryUtils.isEmpty(collectArtifactCiVo) && !BinaryUtils.isEmpty(collectArtifactCiVo.getImgFullName())){
                collectCi.getCiClass().setShape(collectArtifactCiVo.getImgFullName());
            }
            collectCi.getCiClass().setIcon(collectArtifactCiVo.getIcon());
            collectMap.put(ciCode, collectCi);
            ciGroup.computeIfAbsent(ciCode, key -> new HashSet<>()).add(groupCi);
        }
        //排序,下面的数据放到了set里 变成无序了，这步排序应该是没什么用
        List<CcCiInfo> ciInfoList = collectMap.values().stream().filter(each -> !BinaryUtils.isEmpty(each.getCi().getCiLabel()))
                .sorted(Comparator.comparing(each -> each.getCi().getCiLabel())).collect(Collectors.toList());
        List<ActivityDrawingResp> result = new ArrayList<>();
        Set<String> distinctSet = new HashSet<>();
        for(CcCiInfo ccCiInfo : ciInfoList){
            Set<CcCiInfo> targetList = ciGroup.get(ccCiInfo.getCi().getCiCode());
            if(BinaryUtils.isEmpty(targetList)) {
                continue;
            }
            List<CcCiInfo> distinctList = targetList.stream().filter(each -> {
                boolean distinct = !distinctSet.contains(each.getCi().getCiCode());
                //校验主键完整性
                boolean state = each.getCi().getState() != CIState.CREATE_INIT.val();
                return distinct && state;
            }).distinct().collect(Collectors.toList());
            if(!BinaryUtils.isEmpty(distinctList)){
                boolean hasNum = distinctList.get(0).getAttrDefs().stream().anyMatch(each -> NUMBER.equals(each.getProName()));
                if(hasNum){
                    NullComparator<Object> nullComparator = new NullComparator<>();
                    distinctList.sort(Comparator.nullsLast(Comparator.comparing((each -> {
                        String attr = each.getAttrs().get(NUMBER);
                        if(BinaryUtils.isEmpty(attr)){
                            return null;
                        }
                        return attr.matches("\\d+") ? Integer.parseInt(attr) : attr.hashCode();
                    }), nullComparator)));
                }
                ActivityDrawingResp vo = new ActivityDrawingResp().setRole(ccCiInfo).setTask(distinctList);
                result.add(vo);
                Set<String> ciCodeList = targetList.stream().map(each -> each.getCi().getCiCode()).collect(Collectors.toSet());
                distinctSet.addAll(ciCodeList);
            }
        }
        if(BinaryUtils.isEmpty(result)){
            resp.setMessage("未获取到相关数据，或对象数据业务主键未填写完整!");
            return;
        }
        boolean hasNum = result.get(0).getRole().getAttrDefs().stream().anyMatch(each -> NUMBER.equals(each.getProName()));
        if(hasNum){
            NullComparator<Object> nullComparator = new NullComparator<>();
            result.sort(Comparator.nullsLast(Comparator.comparing((each -> {
                String attr = each.getRole().getAttrs().get(NUMBER);
                if(BinaryUtils.isEmpty(attr)){
                    return null;
                }
                return attr.matches("\\d+") ? Integer.parseInt(attr) : attr.hashCode();
            }), nullComparator)));
        }
        resp.setActivityList(result);
        Long roleClassId = result.get(0).getRole().getCi().getClassId();
        Long taskClassId = result.get(0).getTask().get(0).getCi().getClassId();
        if(!BinaryUtils.isEmpty(hierarchy.getEffectClassId()) && !hierarchy.getEffectClassId().equals(0L)){
            if(roleClassId.equals(hierarchy.getEffectClassId())){
                Set<String> ciCodes = result.stream().map(each -> each.getRole().getCi().getCiCode()).collect(Collectors.toSet());
                removeCatalog(dto, ciCodes);
            }else if(taskClassId.equals(hierarchy.getEffectClassId())){
                Set<String> ciCodes = result.stream().map(ActivityDrawingResp::getTask).flatMap(Collection::stream).map(each -> each.getCi().getCiCode()).collect(Collectors.toSet());
                removeCatalog(dto, ciCodes);
            }
        }
    }

    private Map<String, EamArtifactCiVo> getShapeMap(Long artifactId){
        //查询当前制品所有shape
        List<EamArtifactElementVo> elementVos = artifactSvc.queryByArtifactId(artifactId, Collections.singletonList(ArtifactType.ASSET_TYPE.val()));
        List<EamArtifactCiVo> ciElements = elementVos.stream().map(EamArtifactElementVo::getElementCiObj).flatMap(Collection::stream).collect(Collectors.toList());
        return ciElements.stream().collect(Collectors.toMap(EamArtifactCiVo::getId, each -> each, (k1, k2) -> k2));
    }

    private List<String> queryCiCodeByRlt(EamArtifactRltVo rlt, Long classId, Collection<String> ciCodes, String ownerCode){
        VcCiClassInfo rltClass = rlt.getRltClassInfo();
        Long sourceId = rlt.getSourceCiInfo().getId();
        Long targetId = rlt.getTargetCiInfo().getId();
        List<Long> rltId = Collections.singletonList(rltClass.getCiClass().getId());
        List<CcCiRltInfo> rltData = rltSwitchSvc.getRltInfoByClassId(rltId, sourceId, targetId, ownerCode, LibType.PRIVATE);
        List<String> result;
        if(classId.equals(sourceId)){
            result = rltData.stream().filter(each -> ciCodes.contains(each.getSourceCiInfo().getCi().getCiCode()))
                    .map(each->each.getTargetCiInfo().getCi().getCiCode()).collect(Collectors.toList());
        }else{
            result = rltData.stream().filter(each -> ciCodes.contains(each.getTargetCiInfo().getCi().getCiCode()))
                    .map(each->each.getSourceCiInfo().getCi().getCiCode()).collect(Collectors.toList());
        }
        return result;
    }

    /**
     * 通过一条关系数据成图
     */
    private void drawingByOneRlt(QuickDrawingDto dto, QuickDrawingResp resp){
        ESCIInfo ciInfo = dto.getCi();
        EamHierarchyDto hierarchy = dto.getHierarchy();
        Long classId = ciInfo.getClassId();

        EamArtifactRltVo rltVo = hierarchy.getRltList().get(0);
        //取出源端是当前视图绑定ci分类，目标端是层级配置中生成下级目录的分类
        Long sourceId = rltVo.getSourceCiInfo().getId();
        Long targetId = rltVo.getTargetCiInfo().getId();
        if(!classId.equals(sourceId) && !classId.equals(targetId)){
            resp.setMessage("模型配置成图查询数据配置有误!");
            return;
        }
        VcCiClassInfo rltClassInfo = rltVo.getRltClassInfo();
        List<Long> rltId = Collections.singletonList(rltClassInfo.getCiClass().getId());
        List<CcCiRltInfo> rltData = rltSwitchSvc.getRltInfoByClassId(rltId, sourceId, targetId, dto.getOwnerCode(), LibType.PRIVATE);

        Set<String> ciCodes;
        if(classId.equals(sourceId)){
            ciCodes = rltData.stream().filter(each -> each.getSourceCiInfo().getCi().getId().equals(ciInfo.getId()))
                    .map(each -> each.getTargetCiInfo().getCi().getCiCode()).collect(Collectors.toSet());
        } else {
            ciCodes = rltData.stream().filter(each -> each.getTargetCiInfo().getCi().getId().equals(ciInfo.getId()))
                    .map(each -> each.getSourceCiInfo().getCi().getCiCode()).collect(Collectors.toSet());
        }
        if(BinaryUtils.isEmpty(ciCodes)){
            resp.setMessage("通过"+rltVo.getRltClassInfo().getCiClass().getClassName()+SUFFIX);
            return;
        }
        Long queryClassId = classId.equals(sourceId)?targetId:sourceId;
        CcCiClassInfo classInfo = queryClass(queryClassId, hierarchy.getArtifactId());
        resp.setCiClass(classInfo);
        List<ESCIInfo> ciList = queryCiList(new ArrayList<>(ciCodes), queryClassId, dto.getOwnerCode());
        if(BinaryUtils.isEmpty(ciList)){
            resp.setMessage("通过"+rltVo.getRltClassInfo().getCiClass().getClassName()+"关系未获取到相关数据,请查看相关对象数据业务主键是否填写完整!");
            return;
        }
        resp.setCi(sortCiList(ciList));
        if(!BinaryUtils.isEmpty(hierarchy.getEffectClassId()) && hierarchy.getEffectClassId().equals(queryClassId)){
            removeCatalog(dto, ciCodes);
        }
    }

    /**
     * 按序号字段排序
     */
    public List<ESCIInfo> sortCiList(List<ESCIInfo> ciList){
        List<ESCIInfo> numList = new ArrayList<>();
        List<ESCIInfo> stringList = new ArrayList<>();
        List<ESCIInfo> labelList = new ArrayList<>();
        List<ESCIInfo> otherList = new ArrayList<>();
        List<ESCIInfo> result = new ArrayList<>();
        for (ESCIInfo info : ciList) {
            String ciLabel = info.getCiLabel();
            Object num = info.getAttrs().get(NUMBER);
            if(!BinaryUtils.isEmpty(num)){
                //不为空 且 是纯数字，放到numList 其他放到stringList
                if(num instanceof Integer){
                    numList.add(info);
                }else{
                    stringList.add(info);
                }
            }else if(!BinaryUtils.isEmpty(ciLabel)){
                labelList.add(info);
            }else{
                otherList.add(info);
            }
        }
        //根据序号(数值)排序；
        numList.sort((o1, o2) -> {
            if(o1.getAttrs().get(NUMBER).equals(o2.getAttrs().get(NUMBER))){
                return o1.getCiLabel().compareTo(o2.getCiLabel());
            }else{
                return Integer.parseInt(o1.getAttrs().get(NUMBER).toString())-Integer.parseInt(o2.getAttrs().get(NUMBER).toString());
            }
        });
        //根据序号(字符串)排序；
        stringList.sort((o1, o2) -> {
            if(o1.getAttrs().get(NUMBER).equals(o2.getAttrs().get(NUMBER))){
                return o1.getCiLabel().compareTo(o2.getCiLabel());
            }else{
                return o1.getAttrs().get(NUMBER).toString().compareTo(o2.getAttrs().get(NUMBER).toString());
            }
        });
        //没有序号，根据label排序
        labelList.sort(Comparator.comparing(ESCIInfo:: getCiLabel));
        //手动排序
        result.addAll(numList);
        result.addAll(stringList);
        result.addAll(labelList);
        result.addAll(otherList);
        return result;
    }

    private CcCiClassInfo queryClass(Long classId, Long artifactId){
        CcCiClassInfo classInfo = iciClassApiSvc.queryClassInfoById(classId);
        //替换shape
        Map<String, EamArtifactCiVo> shapeMap = getShapeMap(artifactId);
        EamArtifactCiVo artifactVo = shapeMap.get(classInfo.getCiClass().getId().toString());
        if(!BinaryUtils.isEmpty(artifactVo)){
            if(!BinaryUtils.isEmpty(artifactVo.getImgFullName())){
                classInfo.getCiClass().setShape(artifactVo.getImgFullName());
            }else{
                classInfo.getCiClass().setShape(artifactVo.getShape());
            }
            classInfo.getCiClass().setIcon(artifactVo.getIcon());
        }
        return classInfo;
    }

    private List<ESCIInfo> queryCiList(List<String> ciCodes, Long classId, String ownerCode){
        ESCISearchBean bean = new ESCISearchBean();
        bean.setPageNum(1);
        bean.setPageSize(1000);
        bean.setOwnerCode(ownerCode);
        bean.setClassIds(Collections.singletonList(classId));
        bean.setStates(Lists.newArrayList(CIState.CREATE_PENDING, CIState.CREATE_COMPLETE));
        if(!BinaryUtils.isEmpty(ciCodes)){
            bean.setCiCodes(ciCodes);
        }
        Page<ESCIInfo> queryPage = ciSwitchSvc.searchESCIByBean(bean, LibType.PRIVATE);
        return queryPage.getData();
    }
}
